package com.xt;

import com.baidu.aip.ocr.AipOcr;
import java.awt.AWTException;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.*;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.imageio.ImageIO;

import com.sun.org.apache.bcel.internal.generic.IF_ACMPEQ;
import net.dongliu.requests.Requests;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.codec.binary.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.json.JSONArray;
import org.json.JSONObject;
import sun.misc.BASE64Encoder;


public class ExcuteDemo {

    //设置APPID/AK/SK
    public   String APP_ID = "1";
    public   String API_KEY = "1";
    public   String SECRET_KEY = "1";
    private  String CustomUrl = "http://api.jfbym.com/api/YmServer/customApi";
    private   String Token = "1";
    Map headers = new HashMap<>();

    private Map<String,Map<Integer,Integer>> codeMap = new HashMap<>();



    public ExcuteDemo() {
        initCodeMap();
        headers.put("Content-Type", "application/json");
    }

    private  byte[] readBytesFromFile(File file) throws IOException {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        try (InputStream inputStream = new FileInputStream(file)) {
            byte[] buffer = new byte[4096];
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }
        }
        return outputStream.toByteArray();
    }

    /**
     * 识别图片并输出需要点击的目标坐标
     * @return 目标坐标
     */
    private  Map<Integer,Integer> calculateClickCoordinate(File file,List<String> answer) throws IOException {
        Map<Integer,Integer> result = new LinkedHashMap<>();
        byte[] imageBytes = readBytesFromFile(file);
        BASE64Encoder encoder = new BASE64Encoder();
        String verify_type;
        verify_type = "30100";
        com.alibaba.fastjson.JSONObject jsonObject = new com.alibaba.fastjson.JSONObject();
        jsonObject.put("image", encoder.encode(imageBytes));
        if (answer != null) {
            jsonObject.put("extra", String.join(",",answer));
        }
        jsonObject.put("type", verify_type);
        jsonObject.put("token", Token);
        String resp = Requests.post(CustomUrl).headers(headers).jsonBody(jsonObject).send().readToText();
        System.out.println(resp);
        ObjectMapper objectMapper = new ObjectMapper();
        JSONObject value = new JSONObject(resp);
        JSONObject data = value.getJSONObject("data");
        String[] split = data.getString("data").split("\\|");
        for (String s : split) {
            String[] split1 = s.split(",");
            result.put(Integer.parseInt(split1[0]),Integer.parseInt(split1[1]));
        }
        return result;
    }

    public  List<String> getAnswer(File file) throws IOException {
        List<String> result = new ArrayList<>();
        byte[] imageBytes = readBytesFromFile(file);
        AipOcr client = new AipOcr(APP_ID, API_KEY, SECRET_KEY);
        HashMap<String, String> param = new HashMap<>();
        JSONObject jsonObject = client.basicGeneral(imageBytes, param);
        String data = jsonObject.getJSONArray("words_result").getJSONObject(0).getString("words");
        if (data.contains("【") && data.contains("】")) {
            data = data.substring(data.indexOf("【")+1,data.indexOf("】"));
        } else {
            data = data.replace("【","");
            data = data.replace("】","");
        }
        char[] chars = data.toCharArray();
        for (char aChar : chars) {
            String value = String.valueOf(aChar);
            if (Objects.equals(value,",") || Objects.equals(value,"，")) {
                continue;
            }
            result.add(value);
        }
        return result;
    }

    public  String getCode(File file) throws IOException {
        byte[] imageBytes = readBytesFromFile(file);
        AipOcr client = new AipOcr(APP_ID, API_KEY, SECRET_KEY);
        HashMap<String, String> param = new HashMap<>();
        JSONObject jsonObject = client.basicGeneral(imageBytes, param);
        JSONArray wordsResult = jsonObject.getJSONArray("words_result");
        if (wordsResult.length()==0) {
            return null;
        }
        String words = wordsResult.getJSONObject(0).getString("words");
        String replace = words.replace("*", "");
        return replace;
    }


    public void excute(String phoneData,MouseSelectData metaData,String token,String APP_ID,String API_KEY,String SECRET_KEY,String codeToken) {
//        this.API_KEY = API_KEY;
//        this.APP_ID = APP_ID;
//        this.SECRET_KEY = SECRET_KEY;
//        this.Token = codeToken;
        List<String> data = extractPhoneNumbers(phoneData);
        int wordSize = 20;
        Point startPoint = metaData.getStartPoint();
        Element element = new Element((int) startPoint.getX(), (int) startPoint.getY(),metaData.getWidth(),metaData.getHeight());
        //手机号输入框坐标
        for (String phoneNumber : data) {
            System.out.println("开始执行:"+phoneNumber);
            try {
                //复制手机号
                Clipboard copy = copy(phoneNumber);
                //粘贴手机号
                Point phoneNumberPoint = ElementData.PHONE.getClickPoint(element);
                paste(phoneNumberPoint.x, phoneNumberPoint.y, copy);
                //点击发送
                Point sendPoint = ElementData.SEND_BUTTON.getClickPoint(element);
                click(sendPoint.x,sendPoint.y);
                Map<Integer, Integer> clickCoordinate;
                boolean flag = true;
                Point refreshPoint = ElementData.REFRESH.getClickPoint(element);
                ElementData contentPoint = ElementData.ANSWER;
                Point contentPointStartPoint = contentPoint.getStartPoint(element);
                ElementData picture = ElementData.VERIFICATION_PICTURE;
                Point picturePoint = picture.getStartPoint(element);
                ElementData tips = ElementData.TIPS;
                Point tipsPoint = tips.getStartPoint(element);
                while (true) {
                    //如果不是首次进来 需要点击刷新下
                    if (!flag) {
                        click(refreshPoint.x,refreshPoint.y);
                    } else {
                        flag = false;
                    }
                    Thread.sleep(1000);
                    //截取需要输入的文字的图片
                    File content = screenshot(contentPointStartPoint.x, contentPointStartPoint.y,
                            contentPoint.getWidth(element),
                            contentPoint.getHeight(element));
                    List<String> answer = getAnswer(content);
                    //截取图片验证码的图片
                    File screenshot = screenshot(picturePoint.x, picturePoint.y,
                            picture.getWidth(element),
                            picture.getHeight(element));
                    if (Objects.nonNull(codeMap)&&codeMap.containsKey(String.join(",",answer))) {
                        System.out.println("获取缓存的坐标");
                       clickCoordinate = codeMap.get(String.join(",",answer));
                    } else {
                        //获取需要点击的坐标
                        clickCoordinate = calculateClickCoordinate(screenshot,answer);
                    }
                    //如果坐标不是空的 那么就开始点击
                    if (!clickCoordinate.isEmpty()) {
                        //点击图片验证码
                        for (Entry<Integer, Integer> entry : clickCoordinate.entrySet()) {
                            click(picturePoint.x+entry.getKey(),
                                    picturePoint.y+entry.getValue()+wordSize);
                        }
                        //点击完睡眠3秒 等待响应 如果点击失败了 那么提示框还是会包含请依次输入
                        Thread.sleep(3000);
                        //识别下这个位置
                        File result = screenshot(tipsPoint.x, tipsPoint.y,
                                tips.getWidth(element), tips.getHeight(element));
                        String join = getCode(result);
                        if (Objects.isNull(join) || !join.contains("请依次点击")) {
                            codeMap.put(String.join(",",answer),clickCoordinate);
                            break;
                        }
                    }
                }
                //勾选同意的框
                Point clickPoint = ElementData.CHECK_BOX.getClickPoint(element);
                click(clickPoint.x,clickPoint.y);
                copy = copy(getVerCode(token, phoneNumber,0));
                if (Objects.equals(copy,"下一个")) {
                    System.out.println(phoneNumber+"获取验证码失败，号码库删除这个之前的再重新启动");
                    break;
                }
                Point verificationCodePoint = ElementData.CODE.getClickPoint(element);
                paste(verificationCodePoint.x,verificationCodePoint.y,copy);
                //点击确认
                Point enterPoint = ElementData.CONFIRM_BUTTON.getClickPoint(element);
                click(enterPoint.x,enterPoint.y);
                //点击领取
                Point receivePoint = ElementData.RECEIVE.getClickPoint(element);
                click(receivePoint.x,receivePoint.y);
                Point wechatEnter = ElementData.WECHAT_CONFIRM.getClickPoint(element);
                click(wechatEnter.x,wechatEnter.y);
                Thread.sleep(4000);
                //点击切号
                Point switchPoint = ElementData.CHANGE_PHONE.getClickPoint(element);
                click(switchPoint.x,switchPoint.y);
            } catch (Exception e) {
                System.out.println(String.format("%s执行失败,失败原因%s",phoneNumber,e.getMessage()));
            }
        }
        //缓存坐标
        try (FileWriter fileWriter = new FileWriter("data.json")) {
            JSONObject jsonObject = new JSONObject(codeMap);
            fileWriter.write(jsonObject.toString());
            System.out.println("JSON 数据已成功写入文件。");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 点击方法
     * @param x 横坐标
     * @param y 纵坐标
     */
    public static Robot click(int x,int y) throws AWTException, InterruptedException {
        Robot robot = new Robot();
        robot.mouseMove(x, y);
        robot.mousePress(InputEvent.BUTTON1_MASK);
        robot.mouseRelease(InputEvent.BUTTON1_MASK);
        Thread.sleep(2000);
        return robot;
    }

    /**
     * 复制操作
     * @param data 内容
     */
    public static Clipboard copy(String data) {
        //获取粘贴板
        Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
        // 创建一个StringSelection对象，将数据放入其中
        StringSelection selection = new StringSelection(data);
        // 将StringSelection对象设置为剪贴板的内容
        clipboard.setContents(selection, null);
        return clipboard;
    }


    public  void paste(int x,int y,Clipboard clipboard)
            throws IOException, UnsupportedFlavorException, InterruptedException, AWTException {
        Robot robot = click(x, y);
        // 获取剪贴板中的内容
        Transferable contents = clipboard.getContents(null);
        String data = (String) contents.getTransferData(DataFlavor.stringFlavor);
        //移到输入框 并点击
        // 循环遍历字符串的每个字符，并模拟键盘按键事件输入字符
        for (char c : data.toCharArray()) {
            // 获取字符的键码
            int keyCode = KeyEvent.getExtendedKeyCodeForChar(c);
            // 模拟按下按键
            robot.keyPress(keyCode);
            // 模拟释放按键
            robot.keyRelease(keyCode);
            // 等待一段时间，模拟人工输入的速度
            robot.delay(100);
        }
    }

    public  File screenshot(int x,int y,int weight,int high) throws AWTException, IOException {
        Robot robot = new Robot();
        BufferedImage screenshot = robot.createScreenCapture(new Rectangle(x, y, weight, high));
//        // 将截图保存为文件
        File output = new File("screenshot.png");
        ImageIO.write(screenshot, "png", output);
        return output;
    }

    public  File getBrowserScreenshot(int browserX,int browserY,int browserWidth,int browserHeight) throws IOException, AWTException {
        // 创建 Robot 对象
        Robot robot = new Robot();

        // 获取屏幕尺寸
        Rectangle screenRect = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());

        // 截取整个屏幕
        BufferedImage screenCapture = robot.createScreenCapture(screenRect);

        // 根据浏览器窗口的位置和大小裁剪图像
        BufferedImage browserScreenshot = screenCapture.getSubimage(browserX, browserY, browserWidth, browserHeight);

        // 保存截图为文件
        File output = new File("browser_screenshot.png");
        ImageIO.write(browserScreenshot, "png", output);
        return output;
    }



    public  List<String> extractPhoneNumbers(String text) {
        List<String> phoneNumbers = new ArrayList<>();

        // 定义手机号码的正则表达式模式
        String regex = "\\d{11}";

        // 创建 Pattern 对象
        Pattern pattern = Pattern.compile(regex);

        // 创建 Matcher 对象
        Matcher matcher = pattern.matcher(text);

        // 查找匹配的手机号码并添加到列表中
        while (matcher.find()) {
            String phoneNumber = matcher.group();
            phoneNumbers.add(phoneNumber);
        }

        return phoneNumbers;
    }

    public String getVerCode(String token,String phone,int num) {
        String lastFourChars = phone.substring(phone.length() - 4);
        String url = "http://sms.szfangmm.com:3000/api/smslist?token="+token;
        try {
            Thread.sleep(5000);
            // 创建HttpClient对象
            CloseableHttpClient httpClient = HttpClients.createDefault();

            // 创建HttpGet请求对象
            HttpGet httpGet = new HttpGet(url);

            // 发送GET请求
            HttpResponse response = httpClient.execute(httpGet);

            // 获取响应实体
            HttpEntity entity = response.getEntity();

            // 读取响应内容
            String responseString = EntityUtils.toString(entity);
            System.out.println("Response: " + responseString);

            // 关闭响应实体
            EntityUtils.consume(entity);

            // 关闭HttpClient
            httpClient.close();

            // 解析JSON响应并将其转换为对象数组
            JSONArray jsonArray = new JSONArray(responseString);
            for (int i = 0; i < jsonArray.length(); i++) {
                JSONObject jsonObject = jsonArray.getJSONObject(i);
                String simnum = jsonObject.getString("simnum");
                if (simnum.endsWith(lastFourChars)) {
                    String content = jsonObject.getString("content");
                    String pattern = "\\d+"; // 匹配连续的数字

                    Pattern regex = Pattern.compile(pattern);
                    Matcher matcher = regex.matcher(content);
                    if (matcher.find()) {
                        String verificationCode = matcher.group();
                        return verificationCode;
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        num++;
        if (num==5) {
           return "下一个";
        } else {
            return getVerCode(token,phone,num);
        }
    }

    private void initCodeMap() {
        Map<String,Map<Integer,Integer>> result = new HashMap<>();
        try (BufferedReader bufferedReader = new BufferedReader(new FileReader("data.json"))) {
            StringBuilder stringBuilder = new StringBuilder();
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                stringBuilder.append(line);
            }

            String jsonString = stringBuilder.toString();
            if (Objects.nonNull(jsonString) && jsonString.length()!=0) {
                JSONObject jsonObject = new JSONObject(jsonString);
                Map<String, Object> stringObjectMap = jsonObject.toMap();
                if (Objects.nonNull(stringObjectMap)) {
                    for (Entry<String, Object> stringObjectEntry : stringObjectMap.entrySet()) {
                        String key = stringObjectEntry.getKey();
                        Map<Integer,Integer> value = (Map<Integer, Integer>) stringObjectEntry.getValue();
                        result.put(key,value);
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        this.codeMap = result;
    }
}
